using System;
using System.Text;
using System.Runtime.InteropServices;
using GeoFramework.IO;
#if !PocketPC && Framework20
using System.Security;
using System.Runtime.ConstrainedExecution;
#endif

namespace GeoFramework
{
	/// <summary>
	/// Summary description for NativeMethods.
	/// </summary>
#if !PocketPC && Framework20
    [SuppressUnmanagedCodeSecurity]
#endif
    internal 
#if Framework20
		static 
#else
	sealed
#endif
		class NativeMethods
	{
		#region Handle Closing System Calls

		public static bool CloseHandle(SafeFileHandle handle)
		{
			if(handle.IsInvalid)
				return false;
			
#if !PocketPC 
            /* In some cases, a nasty hang can occur if pending 
             * operations are in process when a CloseHandle is called. 
             * This method attempts to prevent such hangs so that
             * the potr can be closed gracefully.
             */
            CancelIo(handle.DangerousGetHandle());
#endif

#if PocketPC
			if(Environment.OSVersion.Platform == System.PlatformID.WinCE)
				return CloseHandleCompact(handle.DangerousGetHandle());
			else
#endif
				return CloseHandleDesktop(handle.DangerousGetHandle());
		}

#if PocketPC
		[DllImport("coredll.dll", EntryPoint = "CloseHandle", SetLastError = false)]
		private static extern bool CloseHandleCompact(IntPtr handle);
#endif

        [DllImport("kernel32.dll", EntryPoint = "CancelIo", SetLastError = false)]
        #if !PocketPC && Framework20
            [SuppressUnmanagedCodeSecurity]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        #endif
        private static extern bool CancelIo(IntPtr hFile);

		[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = false)]
        #if !PocketPC && Framework20
            [SuppressUnmanagedCodeSecurity]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        #endif
		private static extern bool CloseHandleDesktop(IntPtr handle);

		#endregion

		#region Registry System Calls
#if PocketPC && !Framework20

		//private static object RegistrySyncRoot = new object();

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static SafeRegistryHandle RegOpenKeyEx(RootKey rootKey, string lpSubKey, uint ulOptions, int samDesired)
		{
			//lock(RegistrySyncRoot)
			{
				//System.Diagnostics.Debug.WriteLine("RegOpenKeyEx");
				IntPtr phkResult = new IntPtr(-1);

				if(Environment.OSVersion.Platform == PlatformID.WinCE)
				{
					if(RegOpenKeyExCompact((uint)rootKey, lpSubKey, ulOptions, samDesired, ref phkResult) == 0)
						return new SafeRegistryHandle(phkResult, true);
					else
						return null;
				}
				else
				{
					if(RegOpenKeyExDesktop((uint)rootKey, lpSubKey, ulOptions, samDesired, ref phkResult) == 0)
						return new SafeRegistryHandle(phkResult, true);
					else
						return null;
				}
			}
		}

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static SafeRegistryHandle RegCreateKeyEx(RootKey rootKey, string lpSubKey, int lpReserved, string lpClass, RegOption dwOptions, int samDesired, ref int lpSecurityAttributes, ref int lpdwDisposition)
		{
			//lock(RegistrySyncRoot)
			{
				//System.Diagnostics.Debug.WriteLine("RegCreateKeyEx");
				IntPtr phkResult = new IntPtr(-1);

				if(Environment.OSVersion.Platform == PlatformID.WinCE)
				{
					if(RegCreateKeyExCompact((uint)rootKey, lpSubKey, lpReserved, lpClass, dwOptions, samDesired, ref lpSecurityAttributes, ref phkResult, ref lpdwDisposition) == 0)
						return new SafeRegistryHandle(phkResult, true);
					else
						return null;
				}
				else
				{
					if(RegCreateKeyExDesktop((uint)rootKey, lpSubKey, lpReserved, lpClass, dwOptions, samDesired, ref lpSecurityAttributes, ref phkResult, ref lpdwDisposition) == 0)
						return new SafeRegistryHandle(phkResult, true);
					else
						return null;
				}
			}
		}

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static int RegEnumKeyEx(SafeRegistryHandle handle, int iIndex, char[] sKeyName, ref int iKeyNameLen, int iReservedZero, char[] sClassName, ref int iClassNameLen, int iFiletimeZero)
		{
			//lock(handle)
			{
				if(Environment.OSVersion.Platform == PlatformID.WinCE)
					return RegEnumKeyExCompact(handle.DangerousGetHandle(), iIndex, sKeyName, ref iKeyNameLen, iReservedZero, sClassName, ref iClassNameLen, iFiletimeZero);
				else
					return RegEnumKeyExDesktop(handle.DangerousGetHandle(), iIndex, sKeyName, ref iKeyNameLen, iReservedZero, sClassName, ref iClassNameLen, iFiletimeZero);
			}
		}

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static int RegEnumValue(SafeRegistryHandle handle, int iIndex, char[] sValueName, ref int iValueNameLen, int iReservedZero, ref int iType, ref byte[] byData, ref int iDataLen)
		{
			//lock(handle)
			{
				if (Environment.OSVersion.Platform == PlatformID.WinCE)
					return RegEnumValueCompact(handle.DangerousGetHandle(), iIndex, sValueName, ref iValueNameLen, iReservedZero, ref iType, ref byData, ref iDataLen);
				else
				{
					string value = new string(' ', iValueNameLen);
					return RegEnumValueDesktop(handle.DangerousGetHandle(), iIndex, value, ref iValueNameLen, iReservedZero, ref iType, ref byData, ref iDataLen);
				}
			}
		}

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static int RegQueryInfoKey(SafeRegistryHandle handle, char[] lpClass, ref	int lpcbClass, int reservedZero, ref int cSubkey, ref int iMaxSubkeyLen, ref int lpcbMaxSubkeyClassLen, ref int cValueNames, ref int iMaxValueNameLen, ref int iMaxValueLen, int securityDescriptorZero, int lastWriteTimeZero)
		{
			//lock(handle)
			{
				if(Environment.OSVersion.Platform == PlatformID.WinCE)
					return RegQueryInfoKeyCompact(handle.DangerousGetHandle(), lpClass, ref lpcbClass, reservedZero, ref cSubkey, ref iMaxSubkeyLen, ref lpcbMaxSubkeyClassLen, ref cValueNames, ref iMaxValueNameLen, ref iMaxValueLen, securityDescriptorZero, lastWriteTimeZero);
				else
					return RegQueryInfoKeyDesktop(handle.DangerousGetHandle(), lpClass, ref lpcbClass, reservedZero, ref cSubkey, ref iMaxSubkeyLen, ref lpcbMaxSubkeyClassLen, ref cValueNames, ref iMaxValueNameLen, ref iMaxValueLen, securityDescriptorZero, lastWriteTimeZero);
			}
		}

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static int RegQueryValueEx(SafeRegistryHandle handle, string lpValueName, int lpReserved, ref	int lpType, byte[] lpData, ref int lpcbData)
		{
			//lock(handle)
			{
				if(Environment.OSVersion.Platform == PlatformID.WinCE)
					return RegQueryValueExCompact(handle.DangerousGetHandle(), lpValueName, lpReserved, ref lpType, lpData, ref lpcbData);
				else
					return RegQueryValueExDesktop(handle.DangerousGetHandle(), lpValueName, lpReserved, ref lpType, lpData, ref lpcbData);
			}
		}

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static int RegSetValueEx(SafeRegistryHandle handle, string lpValueName, int lpReserved, int lpType, byte[] lpData, int lpcbData)
		{
			//lock(handle)
			{
				if(Environment.OSVersion.Platform == PlatformID.WinCE)
					return RegSetValueExCompact(handle.DangerousGetHandle(), lpValueName, lpReserved, lpType, lpData, lpcbData);
				else
					return RegSetValueExDesktop(handle.DangerousGetHandle(), lpValueName, lpReserved, lpType, lpData, lpcbData);
			}
		}					

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static int RegDeleteKey(SafeRegistryHandle handle, string keyName)
		{
			//lock(handle)
			{
				if(Environment.OSVersion.Platform == PlatformID.WinCE)
					return RegDeleteKeyCompact(handle.DangerousGetHandle(), keyName);
				else
					return RegDeleteKeyDesktop(handle.DangerousGetHandle(), keyName);
			}
		}

#if !PocketPC
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
#endif
		public static int RegDeleteValue(SafeRegistryHandle handle, string valueName)
		{
			//lock(handle)
			{
				if(Environment.OSVersion.Platform == PlatformID.WinCE)
					return RegDeleteValueCompact(handle.DangerousGetHandle(), valueName);
				else
					return RegDeleteValueDesktop(handle.DangerousGetHandle(), valueName);
			}
		}

		#region	Compact Framework P/Invokes

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegCreateKeyEx")]
		private static extern int RegCreateKeyExCompact(uint hKey, string lpSubKey, int lpReserved, string lpClass, RegOption dwOptions, int samDesired, ref int lpSecurityAttributes, ref IntPtr phkResult, ref int lpdwDisposition);

		[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true, EntryPoint = "RegCreateKeyEx")]
		private static extern int RegCreateKeyExDesktop(uint hKey, string lpSubKey, int lpReserved, string lpClass, RegOption dwOptions, int samDesired, ref int lpSecurityAttributes, ref IntPtr phkResult, ref int lpdwDisposition);


		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegOpenKeyEx")]
		private static extern int RegOpenKeyExCompact(uint hKey, string subKey, uint options, int sam, ref IntPtr phkResult);

		[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError=true, EntryPoint = "RegOpenKeyEx")]
		private static extern int RegOpenKeyExDesktop(uint hKey, string subKey, uint options, int sam, ref IntPtr phkResult);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegEnumKeyEx")]
		private static extern int RegEnumKeyExCompact(IntPtr hKey, int iIndex, char[] sKeyName, ref int iKeyNameLen, int iReservedZero, char[] sClassName, ref int iClassNameLen, int iFiletimeZero);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegEnumValue")]
		private static extern int RegEnumValueCompact(IntPtr hKey, int iIndex, char[] sValueName, ref	int iValueNameLen, int iReservedZero, ref int iType, ref byte[] byData, ref int iDataLen);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegQueryInfoKey")]
		private static extern int RegQueryInfoKeyCompact(IntPtr hKey, char[] lpClass, ref	int lpcbClass, int reservedZero, ref int cSubkey, ref int iMaxSubkeyLen, ref int lpcbMaxSubkeyClassLen, ref int cValueNames, ref int iMaxValueNameLen, ref int iMaxValueLen, int securityDescriptorZero, int lastWriteTimeZero);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegQueryValueEx")]
		private static extern int RegQueryValueExCompact(IntPtr hKey, string lpValueName, int lpReserved, ref	int lpType, byte[] lpData, ref int lpcbData);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegSetValueExW")]
		private static extern int RegSetValueExCompact(IntPtr hKey, string lpValueName, int lpReserved, int lpType, byte[] lpData, int lpcbData);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegCloseKey")]
		private static extern int RegCloseKeyCompact(IntPtr hKey);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegDeleteKey")]
		private static extern int RegDeleteKeyCompact(IntPtr hKey, string keyName);

		[DllImport("coredll.dll", SetLastError = false, EntryPoint = "RegDeleteValue")]
		private static extern int RegDeleteValueCompact(IntPtr hKey, string valueName);

		#endregion

		#region Desktop Framework P/Invokes




		[DllImport("advapi32.dll", SetLastError=true, EntryPoint = "RegEnumKeyEx")]
		private static extern int RegEnumKeyExDesktop(IntPtr hKey, int iIndex, char[] sKeyName, ref int iKeyNameLen, int iReservedZero, char[] sClassName, ref int iClassNameLen, int iFiletimeZero);

		//[DllImport("advapi32.dll", EntryPoint = "RegEnumValue")]
		[DllImport("advapi32.dll", SetLastError=true, EntryPoint = "RegEnumValueA")]
		private static extern int RegEnumValueDesktop(IntPtr hKey, int dwIndex, string lpValueName, ref int lpcbValueName, int lpReserved, ref int lpType, ref byte[] lpData, ref int lpcbData);

		//public static extern int RegEnumValueDesktop(IntPtr hKey, int iIndex, char[] lpValueName, ref int lpcbValueName, int lpReserved, ref int lpType, ref byte[] lpData, ref int lpcbData);
		//private static extern int RegEnumValueDesktop(IntPtr hKey, int iIndex, char[] sValueName, ref	int iValueNameLen, int iReservedZero, ref int iType, ref byte[] byData, ref	int iDataLen);

		[DllImport("advapi32.dll", SetLastError=true, EntryPoint = "RegQueryInfoKey")]
		private static extern int RegQueryInfoKeyDesktop(IntPtr hKey, char[] lpClass, ref	int lpcbClass, int reservedZero, ref int cSubkey, ref int iMaxSubkeyLen, ref int lpcbMaxSubkeyClassLen, ref int cValueNames, ref int iMaxValueNameLen, ref int iMaxValueLen, int securityDescriptorZero, int lastWriteTimeZero);

		[DllImport("advapi32.dll", SetLastError=true, EntryPoint = "RegQueryValueEx")]
		private static extern int RegQueryValueExDesktop(IntPtr hKey, string lpValueName, int lpReserved, ref	int lpType, byte[] lpData, ref int lpcbData);

		[DllImport("advapi32.dll", SetLastError=true, EntryPoint = "RegSetValueExW")]
		private static extern int RegSetValueExDesktop(IntPtr hKey, string lpValueName, int lpReserved, int lpType, byte[] lpData, int lpcbData);

		[DllImport("advapi32.dll", SetLastError=true, EntryPoint = "RegDeleteKey")]
		private static extern int RegDeleteKeyDesktop(IntPtr hKey, string keyName);

		[DllImport("advapi32.dll", SetLastError=true, EntryPoint = "RegDeleteValue")]
		private static extern int RegDeleteValueDesktop(IntPtr hKey, string valueName);

		#endregion
#endif
        #endregion

#if PocketPC && !Smartphone
        #region Power Notification API

        [DllImport("coredll")]
        public static extern IntPtr CreateMsgQueue(string Name, MSGQUEUEOPTIONS Options);

        [DllImport("coredll")]
        public static extern bool ReadMsgQueue(
            IntPtr hMsgQ,
            byte[] lpBuffer,
            int cbBufferSize,
            out int lpNumberOfBytesRead,
            int dwTimeout,
            out int pdwFlags
            );

        [DllImport("coredll")]
        public static extern IntPtr CreateEvent(int dwReserved1, bool bManualReset, bool bInitialState, string Name);

        [DllImport("coredll")]
        public static extern bool EventModify(IntPtr hEvent, int func);

        //[DllImport("coredll")]
        //static extern bool CloseHandle(IntPtr h); 

        [DllImport("coredll")]
        public static extern IntPtr RequestPowerNotifications(IntPtr hMsgQ, PowerEventType Flags);

        [DllImport("coredll")]
        public static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);


        #endregion
#endif

#if PocketPC
        #region Host Platform Determination

        [System.Runtime.InteropServices.DllImport("coredll.dll", EntryPoint = "SystemParametersInfo", SetLastError = true)]
        public extern static Boolean GetSystemParameterString(uint sysParam, UInt32 bufferSize, StringBuilder stringBuffer, Boolean updateWinIni);

        #endregion
#endif
    }
}
